#region Using References

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Color = System.Drawing.Color;
using Gdi = System.Drawing.Imaging;

#endregion

namespace Beaker.OpenCube.Drawing
{
	public static class GdiWpfExtension
	{
		private static class NativeMethods
		{
			[DllImport( "gdi32.dll" )]
			public static extern bool DeleteObject( IntPtr hObject );
		}

		/// <summary>
		/// Create an ImageSource from the Gdi Bitmap
		/// </summary>
		/// <param name="bitmap">The bitmap.</param>
		/// <returns>An ImageSource</returns>
		public static ImageSource ToImageSource( this Bitmap bitmap )
		{
			IntPtr hBitmap = IntPtr.Zero;
			try
			{
				hBitmap = bitmap.GetHbitmap();

				return Imaging.CreateBitmapSourceFromHBitmap(
					hBitmap, IntPtr.Zero,
					Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight( 16, 16 )
				);
			}
			finally
			{
				if( hBitmap != IntPtr.Zero )
					NativeMethods.DeleteObject( hBitmap );
			}
		}

		public static BitmapSource CreateBitmapSource( this Bitmap bitmap )
		{
			var rect = new Rectangle( 0, 0, bitmap.Width, bitmap.Height );
			Gdi.BitmapData bitmapData = bitmap.LockBits( rect, Gdi.ImageLockMode.ReadOnly, bitmap.PixelFormat );
			try
			{
				BitmapSource source = BitmapSource.Create( bitmap.Width, bitmap.Height, bitmap.HorizontalResolution, bitmap.VerticalResolution, bitmap.PixelFormat.ToWpfPixelFormat(), null, bitmapData.Scan0, bitmapData.Stride * bitmap.Height, bitmapData.Stride );

				return source;
			}
			finally
			{
				bitmap.UnlockBits( bitmapData );
			}
		}

		/// <summary>
		/// Enumerate over all the pixels in the image as a sequence of Colors.
		/// </summary>
		/// <param name="bitmap">The bitmap to enumerate.</param>
		/// <param name="rect">The rectangle of the part of the image to enumerate.</param>
		/// <returns></returns>
		public static IEnumerable<Color> Pixels( this Bitmap bitmap, Rectangle rect )
		{
			// TODO: Implement using LockBits and maybe unsafe
			//Gdi.BitmapData bitmapData = bitmap.LockBits( rect, Gdi.ImageLockMode.ReadOnly, bitmap.PixelFormat );
			//try
			//{
				int y1 = rect.Top;
				int y2 = rect.Bottom;
				int x1 = rect.Left;
				int x2 = rect.Right;

				for( int y = y1; y < y2; y++ )
				{
					for( int x = x1; x < x2; x++ )
					{
						yield return bitmap.GetPixel( x, y );
					}
				}
			//}
			//finally
			//{
			//	bitmap.UnlockBits( bitmapData );
			//}
		}

		/// <summary>
		/// Converts a C# GDI+ pixel format, to a WPF Pixel Format
		/// </summary>
		/// <param name="gdiFormat">The GDI format.</param>
		/// <returns></returns>
		/// <exception cref="System.NotSupportedException">When the pixel format is not supported by WPF</exception>
		public static PixelFormat ToWpfPixelFormat( this Gdi.PixelFormat gdiFormat )
		{
			switch( gdiFormat )
			{
				// 1 bit
				case Gdi.PixelFormat.Format1bppIndexed:
					return PixelFormats.Indexed1;

				// 4 bits
				case Gdi.PixelFormat.Format4bppIndexed:
					return PixelFormats.Indexed4;

				// 8 bits
				case Gdi.PixelFormat.Format8bppIndexed:
					return PixelFormats.Indexed8;

				// 16 bits
				case Gdi.PixelFormat.Format16bppGrayScale:
					return PixelFormats.Gray16;
				case Gdi.PixelFormat.Format16bppRgb555:
					return PixelFormats.Bgr555;
				case Gdi.PixelFormat.Format16bppRgb565:
					return PixelFormats.Bgr565;

				// 24 bits
				case Gdi.PixelFormat.Format24bppRgb:
					return PixelFormats.Bgr24;

				// 32 bits
				case Gdi.PixelFormat.Format32bppRgb:
					return PixelFormats.Bgr32;
				case Gdi.PixelFormat.Format32bppArgb:
					return PixelFormats.Bgra32;
				case Gdi.PixelFormat.Format32bppPArgb:
					return PixelFormats.Pbgra32;

				// 64 bits
				case Gdi.PixelFormat.Format64bppArgb:
					return PixelFormats.Rgba64;
				case Gdi.PixelFormat.Format64bppPArgb:
					return PixelFormats.Prgba64;
			}

			throw new NotSupportedException();
		}
	}
}